package org.nightknight.satobee.core;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Conversation {
    
    public static Contact me;
    
    public static final String connectFailed = "Connect Failed!!!";
    
    private List<IUsrOutListener> usrOutListeners = new ArrayList<IUsrOutListener>();
    private List<IMesRecListener> listeners = new ArrayList<IMesRecListener>();

    private Socket s = null;
    private Contact contact;
    private int port = 8199;
    
    //监听端口接收到的信息，并触发事件，当socket被关闭时终止线程
    private Thread listener = new Thread() {

        @Override
        public void run() {
            if (null != s && s.isConnected()) {
                try {
//                    InputStream in = new BufferedInputStream(s.getInputStream(), 1024);
                    Scanner in = new Scanner(s.getInputStream());
                    String message = null;

                    while (s.isConnected() && in.hasNextLine()) {
                        message = in.nextLine();
                        Message mes = decodeMessage(message);
                        fireMessageReceivedListners(mes);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    };
    
    static {
        try {
            me = new Contact(InetAddress.getLocalHost());
        } catch (UnknownHostException ex) {
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 初始化一个Socket，之后的使用之前需要先连接上服务器，调用connect方法。
     */
    public Conversation() {
    }

    /**
     * 构造函数，同时连接上服务器
     * @param contact 会话的另一方
     */
    public Conversation(Contact contact) {
        this.contact = contact;
        this.connect(contact);
    }

    /**
     * 直接将一个构造好的Socket传进来，用于封装服务器端接受的Socket
     * @param s
     */
    public Conversation(Socket s) {
        this.s = s;
        contact = new Contact(s.getInetAddress());

        listener.start();
    }

    /**
     * 关闭连接
     */
    public void closeConnection() {
        try {
            this.s.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    /**
     * 连接到指定的服务器
     * @param url
     * @param port
     */
    public final boolean connect(Contact contact) {
        try {
            if (null == s) {
                s = new Socket(contact.getAddresss(), port);
            } else if (s.isClosed()) {
                s.connect(new InetSocketAddress(contact.getAddresss(), port));
            }
            
            System.out.println("Connect to " + contact.getAddresss() + " at " + s.getLocalPort() + " successfully!");
            System.out.println("Enter bye to exit.");

            listener.start();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, e);
            return false;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, e);
            return false;
        }
        
        return true;
    }

    /**
     * 向服务器端发送信息
     * @param message 所要发送的信息
     * @return boolean 发送是否成功
     */
    public boolean sendMessage(Message mes) {
        String message = mes.getContent();
        if (s.isClosed() && !this.connect(contact)) {
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, connectFailed);
            this.fireIUsrOutListener(contact);
            return false;
        }
        
        try {
            PrintWriter out = new PrintWriter(s.getOutputStream(), true);
            //如果输入的是“bye”的话则结束连接
            if (message.trim().equalsIgnoreCase("bye")) {
                s.close();
            }
            out.println(message);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(Conversation.class.getName()).log(Level.SEVERE, null, e);
            return false;
        }
        
        return true;
    }
    
    private String encodeMessage(Message message) {
        StringBuilder builder = new StringBuilder(message.getContent());
        int index = 0;
        int occurence = 0;
        while ((occurence = builder.indexOf("\r", index)) != -1) {
            builder.replace(occurence, occurence + 1, "\r\r");
            index = occurence + 2;
        }
        index = 0;
        while ((occurence = builder.indexOf("\n")) != -1) {
            builder.replace(occurence, occurence + 1, "\r");
            index = occurence + 1;
        }
        
        builder.insert(0, message.getType());
        builder.insert(0, message.geteSendTime().getTime());
        
        return builder.toString();
    }
    
    private Message decodeMessage(String message) {
        Message mes = new Message();
        mes.setContent(message);
        mes.setReceiver(me);
        mes.setSender(contact);
        
        StringBuilder builder = new StringBuilder(message);
        int occurence = 0, index = 0;
        while ((occurence = builder.indexOf("\r\r", index)) != -1) {
            builder.replace(occurence, occurence + 2, "\r");
            index = occurence + 1;
        }
        index = 0;
        while ((occurence = builder.indexOf("\r")) != -1) {
            builder.replace(occurence, occurence + 1, "\n");
            index = occurence + 1;
        }
        mes.setSendTime(new Date());
        mes.setType(1);
        
        return mes;
    }

    public Socket getSocket() {
        return this.s;
    }
    
    public Contact getContact() {
        return this.contact;
    }

    /**
     * 添加一个监听器
     * @param listener
     */
    public void addMessageReceivedListener(IMesRecListener listener) {
        this.listeners.add(listener);
    }

    /**
     * 删除一个监听器
     * @param listener
     * @return
     */
    public boolean removeMessageReceivedListener(IMesRecListener listener) {
        return this.listeners.remove(listener);
    }

    /**
     * 触发所有的监听器
     * @param message
     */
    public void fireMessageReceivedListners(Message message) {
        for (IMesRecListener lis : this.listeners) {
            lis.messageReceived(message);
        }
    }

    public final void addIUsrOutListener(IUsrOutListener listener) {
        this.usrOutListeners.add(listener);
    }

    public void removeIUsrOutListener(IUsrOutListener listener) {
        this.usrOutListeners.remove(listener);
    }

    public void fireIUsrOutListener(Contact contact) {
        for (IUsrOutListener listener : usrOutListeners) {
            listener.userLogout(contact);
        }
    }
}